package com.zhongkun.datahome.service.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zhongkun.datahome.common.enums.DataSettingLinkTypeEnum;
import com.zhongkun.datahome.common.core.domain.entity.SysRole;
import com.zhongkun.datahome.common.utils.SecurityUtils;
import com.zhongkun.datahome.core.mapper.SysRoleDataSettingMapper;
import com.zhongkun.datahome.core.repository.TenantUserRepository;
import com.zhongkun.datahome.service.domain.MiniProgramDataSetting;
import com.zhongkun.datahome.service.domain.MiniProgramNodeSetting;
import com.zhongkun.datahome.service.domain.MiniProgramVisionSetting;
import com.zhongkun.datahome.service.mapper.DataAssetsMapper;
import com.zhongkun.datahome.service.mapper.MiniProgramDataSettingMapper;
import com.zhongkun.datahome.service.mapper.MiniProgramNodeSettingMapper;
import com.zhongkun.datahome.service.mapper.MiniProgramVisionSettingMapper;
import com.zhongkun.datahome.service.req.cmd.system.MiniProgramDataSettingCmd;
import com.zhongkun.datahome.service.req.cmd.system.MiniProgramNodeSettingCmd;
import com.zhongkun.datahome.service.req.cmd.system.MiniProgramVisionSettingCmd;
import com.zhongkun.datahome.service.res.setting.AppDataSettingVo;
import com.zhongkun.datahome.service.res.setting.AppVisionSettingVo;
import com.zhongkun.datahome.service.res.system.MiniProgramDataSettingVo;
import com.zhongkun.datahome.service.service.ISystemSettingService;
import com.zhongkun.datahome.service.utils.StreamUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: MinKun
 * @Date: Created in 2025/5/7
 * @Description:
 */
@Slf4j
@Service
public class SystemSettingServiceImpl implements ISystemSettingService {

    @Resource
    private MiniProgramDataSettingMapper miniProgramDataSettingMapper;

    @Resource
    private DataAssetsMapper dataAssetsMapper;

    @Resource
    private MiniProgramVisionSettingMapper miniProgramVisionSettingMapper;

    @Resource
    private MiniProgramNodeSettingMapper miniProgramNodeSettingMapper;

    @Resource
    private SysRoleDataSettingMapper sysRoleDataSettingMapper;

    @Resource
    private TenantUserRepository tenantUserRepository;

    @Override
    @Transactional
    public Boolean addMiniProgramDataSetting(MiniProgramDataSettingCmd cmd) {
        MiniProgramDataSetting entity = new MiniProgramDataSetting();
        entity.setId(null);
        BeanUtils.copyProperties(cmd, entity);
        return miniProgramDataSettingMapper.insert(entity) > 0;
    }

    @Override
    @Transactional
    public Boolean updateMiniProgramDataSetting(MiniProgramDataSettingCmd cmd) {
        MiniProgramDataSetting entity = new MiniProgramDataSetting();
        BeanUtils.copyProperties(cmd, entity);
        boolean updateSuccess = miniProgramDataSettingMapper.updateById(entity) > 0;
//        if (updateSuccess) {
//            dataAssetsMapper.updateAssetsType(cmd.getId(), cmd.getName());
//        }
        return updateSuccess;
    }

    @Override
    public boolean queryHasChildDataSetting(Long id) {
        return miniProgramDataSettingMapper.queryCountByParentId(id) > 0;
    }

    @Override
    public List<MiniProgramDataSettingVo> listCustomerDataSetting() {
        // 查询全部末级类目
        List<MiniProgramDataSettingVo> dataSettingVos = miniProgramDataSettingMapper.queryListByLevel(0);
        return dataSettingVos.stream()
                .filter(item -> DataSettingLinkTypeEnum.OTHER.is(item.getLinkType()))
                .collect(Collectors.toList());
    }

    @Override
    public <T> void batchSetDataSettingName(List<T> list, Function<T, Long> getId, BiConsumer<T, String> setName) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        List<Long> dataSettingIds = list.stream().map(getId).collect(Collectors.toList());
        List<MiniProgramDataSetting> miniProgramDataSettings = miniProgramDataSettingMapper.selectBatchIds(dataSettingIds);
        Map<Long, String> nameMap =
                StreamUtil.listToMap(miniProgramDataSettings, MiniProgramDataSetting::getId, MiniProgramDataSetting::getName);

        list.forEach(item -> setName.accept(item, nameMap.get(getId.apply(item))));
    }

    @Override
    @Transactional(readOnly = true)
    public List<MiniProgramDataSettingVo> queryMiniProgramDataSettingList(Integer level) {
        List<MiniProgramDataSettingVo> list = null;
        if (level == null) {
            list = miniProgramDataSettingMapper.queryAllList();
        } else {
            list = miniProgramDataSettingMapper.queryListByLevel(level);
        }

        if (list != null) {
            list.forEach(vo -> {
                if (vo.getParentId() != null) {
                    vo.setParentName(miniProgramDataSettingMapper.queryNameById(vo.getParentId()));
                }
            });
        }

        tenantUserRepository.batchSetUserName(list, MiniProgramDataSettingVo::getUpdateBy, MiniProgramDataSettingVo::setUpdateByName);
        return list;
    }

    @Override
    @Transactional
    public Boolean delMiniProgramDataSetting(Long id) {
        Boolean delSuccess = false;
        int dataCount = dataAssetsMapper.selectCountByAssetsTypeId(id);
        if (dataCount <= 0) {
            delSuccess = miniProgramDataSettingMapper.deleteById(id) > 0;
        }
        return delSuccess;
    }

    @Override
    public Boolean queryMiniProgramDataSettingHasAssets(Long id) {
        return dataAssetsMapper.selectCountByAssetsTypeId(id) > 0;
    }

    @Override
    public MiniProgramDataSetting queryById(Long id) {
        return miniProgramDataSettingMapper.selectById(id);
    }

    @Override
    @Transactional(readOnly = true)
    public List<MiniProgramVisionSetting> queryAllVisionSetting() {
        return miniProgramVisionSettingMapper.queryAllList();
    }

    @Override
    @Transactional
    public void batchAddMiniProgramVisionSetting(List<MiniProgramVisionSettingCmd> cmdList) {
        if (cmdList != null && !cmdList.isEmpty()) {
            miniProgramVisionSettingMapper.deleteAll();
            cmdList.forEach(cmd -> {
                MiniProgramVisionSetting entity = new MiniProgramVisionSetting();
                BeanUtils.copyProperties(cmd, entity);
                miniProgramVisionSettingMapper.insert(entity);
            });
        }
    }

    @Override
    @Transactional
    public Boolean addMiniProgramVisionSetting(MiniProgramVisionSettingCmd cmd) {
        MiniProgramVisionSetting entity = new MiniProgramVisionSetting();
        BeanUtils.copyProperties(cmd, entity);
        int insertCount = miniProgramVisionSettingMapper.insert(entity);
        return insertCount > 0;
    }

    @Override
    @Transactional
    public Boolean updateMiniProgramVisionSetting(MiniProgramVisionSettingCmd cmd) {
        return miniProgramVisionSettingMapper.updateByCode(cmd.getUrl(), cmd.getCode()) > 0;
    }

    @Override
    @Transactional
    public Boolean delMiniProgramVisionSetting(String code) {
        return miniProgramVisionSettingMapper.updateByCode("", code) > 0;
    }

    @Override
    public List<AppVisionSettingVo> getMiniProgramVisionSettings() {
        List<MiniProgramVisionSetting> visionSettings = miniProgramVisionSettingMapper.selectList(new LambdaQueryWrapper<>());
        return visionSettings.stream().map(AppVisionSettingVo::of).collect(Collectors.toList());
    }

    @Override
    public List<AppDataSettingVo> getMiniProgramDataSettings(Boolean employeeFlag) {
        // 查询全部图标
        List<MiniProgramDataSetting> dataSettings = miniProgramDataSettingMapper.selectList(new LambdaQueryWrapper<>());

        // 员工 需要对角色资料图标进行过滤
        if ((Objects.isNull(employeeFlag) && SecurityUtils.getLoginUser().getUser().isEmployee())
                || (Objects.nonNull(employeeFlag) && employeeFlag)) {
            List<Long> currentUserDataSettingIds = getCurrentUserDataSettingIds();
            dataSettings.removeIf(item -> !currentUserDataSettingIds.contains(item.getId()));
        }

        List<AppDataSettingVo> appDataSettingVos = dataSettings.stream()
                .map(AppDataSettingVo::of)
                .collect(Collectors.toList());

        Map<Long, List<AppDataSettingVo>> parentIdGroupMap =
                StreamUtil.listGroupBy(appDataSettingVos, AppDataSettingVo::getParentId);

        appDataSettingVos.forEach(item -> {
            if (parentIdGroupMap.containsKey(item.getId())) {
                item.setAndSortChildren(parentIdGroupMap.get(item.getId()));
            }
        });

        return appDataSettingVos.stream()
                .filter(item -> item.getParentId() == 0)
                .sorted(Comparator.comparingInt(AppDataSettingVo::getSort))
                .collect(Collectors.toList());
    }

    private List<Long> getCurrentUserDataSettingIds() {
        List<Long> roleIds = Optional.ofNullable(SecurityUtils.getLoginUser().getUser().getRoles()).orElse(Collections.emptyList())
                .stream()
                .map(SysRole::getRoleId)
                .collect(Collectors.toList());

        return CollectionUtils.isEmpty(roleIds) ?
                Collections.emptyList() : sysRoleDataSettingMapper.getDataSettingIds(roleIds);
    }

    @Override
    public List<Long> getDataSettingtIdsByRoleId(Long roleId) {
        return sysRoleDataSettingMapper.getDataSettingIds(Collections.singletonList(roleId));
    }

    @Override
    public List<MiniProgramDataSetting> getDataSettingTree() {
        // 查询全部图标.
        List<MiniProgramDataSetting> dataSettings = miniProgramDataSettingMapper.selectList(new LambdaQueryWrapper<>());

        // 非管理员 需要对角色资料图标进行过滤
        if (!SecurityUtils.getLoginUser().getUser().isAdminEmployee()) {
            List<Long> currentUserDataSettingIds = getCurrentUserDataSettingIds();
            dataSettings.removeIf(item -> !currentUserDataSettingIds.contains(item.getId()));
        }

        Map<Long, List<MiniProgramDataSetting>> parentIdGroupMap =
                StreamUtil.listGroupBy(dataSettings, MiniProgramDataSetting::getParentId);

        dataSettings.forEach(item -> {
            if (parentIdGroupMap.containsKey(item.getId())) {
                List<MiniProgramDataSetting> children = parentIdGroupMap.get(item.getId());
                children.sort(Comparator.comparingInt(MiniProgramDataSetting::getSort));
                item.setChildren(children);
            }
        });

        return dataSettings.stream()
                .filter(item -> item.getParentId() == 0)
                .sorted(Comparator.comparingInt(MiniProgramDataSetting::getSort))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public Boolean addMiniProgramNodeSetting(MiniProgramNodeSettingCmd cmd) {
        MiniProgramNodeSetting entity = new MiniProgramNodeSetting();
        BeanUtils.copyProperties(cmd, entity);
        if (entity.getSort() == null) {
            Integer maxSort = miniProgramNodeSettingMapper.selectMaxSort();
            if (maxSort == null) {
                maxSort = 0;
            }
            entity.setSort(++maxSort);
        }
        return miniProgramNodeSettingMapper.insert(entity) > 0;
    }

    @Override
    @Transactional
    public Boolean delMiniProgramNodeSetting(Long id) {
        return miniProgramNodeSettingMapper.deleteById(id) > 0;
    }

    @Override
    @Transactional(readOnly = true)
    public List<MiniProgramNodeSettingCmd> queryMiniProgramNodeSetting() {
        return miniProgramNodeSettingMapper.queryNodeList();
    }

    @Override
    @Transactional
    public void batchSaveMiniProgramNodeSetting(List<MiniProgramNodeSettingCmd> cmdList) {
        miniProgramNodeSettingMapper.deleteAllNode();
        if (cmdList != null && !cmdList.isEmpty()) {
            cmdList.forEach(cmd -> {
                MiniProgramNodeSetting entity = new MiniProgramNodeSetting();
                BeanUtils.copyProperties(cmd, entity);
                if (entity.getSort() == null) {
                    Integer maxSort = miniProgramNodeSettingMapper.selectMaxSort();
                    if (maxSort == null) {
                        maxSort = 0;
                    }
                    entity.setSort(++maxSort);
                }
                miniProgramNodeSettingMapper.insert(entity);
            });
        }
    }
}
